package com.huiyeji.xlsx;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;

public abstract class AbstractXLSXProcessor implements FileProcessor{

    public AbstractXLSXProcessor(){
        Processor annotation = getProcessorAnno();
        FileProcessExecutor.registerProcessor(annotation,this);
    }

    @Override
    public Workbook process(MultipartFile file, Map<String, Object> params) {
        //文件校验
        c(file);
        //构建文件操作空间
        XLSXWorkSpace wk = new XLSXWorkSpace(file);
        //属性名重复校验
        b(wk);
        //获得处理器名称
        String pN =(String) params.get(FileProcessExecutor.PROCESSOR_NAME);
        //文件前置处理
        preProcess(wk,params);
        //文件解析和处理
        a(wk,params,pN);
        //文件后置处理
        postProcess(wk,params);
        return wk.getWorkbook();
    }

    private void a(XLSXWorkSpace workSpace, Map<String, Object> params,String processorName){
        Row cR;
        c cC;
        XLSXRowContext ctx;
        List<DataColumn> cls;
        //初始化自定义数据容器
        List<Container> cts = registerContainer(params);
        //遍历所有可用行
        Iterator<Row> rowIterator = workSpace.getSheet().rowIterator();
        while (rowIterator.hasNext()){
            cR = rowIterator.next();
            if (cR.getRowNum() < 2){
                continue;
            }
            //构建行操作器
            cC = new c(workSpace.getWorkbook(),cR,workSpace.getColumnCount());

            //构建数据列集合
            cls = new ArrayList<>();

            Cell cell;

            //分析所有列
            for (int columnNum = 0; columnNum < workSpace.getColumnCount(); columnNum++) {
                a a = workSpace.gSci(columnNum);
                String cV = null;
                cell = cR.getCell(columnNum);
                if (cell != null){
                    int cellType = cell.getCellType();
                    if (cellType != Cell.CELL_TYPE_BLANK){
                        cell.setCellType(1);
                        cV = cell.getStringCellValue();
                    }
                }
                a.setCv(cV);

                //数据列处理
                e(a);

                //数据列解析、转换
                a.setCv(parseColumnValue(cV));

                //构建并注册数据列
                cls.add(new DataColumn(a, cC));
            }

            //构建行数据上下文
            ctx = new XLSXRowContext(cls,cts, cC,cR.getRowNum());

            try{
                //行数据处理
                doRowProcess(ctx,params);
            }catch (Exception exception){
                //异常处理
                doRowError(ctx,params,exception);
            } finally {
                //行数据后置处理
                try{
                    doRowFinally(ctx,params);
                }catch (Exception exception){
                    ctx.appendWrite("行数据后置处理失败,原因:"+exception.getMessage(),ContentType.FAILED);
                }
            }

            //记录文件处理进度
            //recordProgress(processorName,(context.getRowNumber()-2)+"/"+(workSpace.getRowCount()-2));
        }
    }

    /**
     * 注册自定义数据容器
     * @return List<Container>
     */
    public List<Container> registerContainer(Map<String, Object> params) {
        return new ArrayList<>();
    }

    /**
     * 文件后续处理
     * @param workSpace 操作空间
     * @param params 参数
     */
    public void postProcess(XLSXWorkSpace workSpace,Map<String, Object> params){

    };

    /**
     * 文件操作空间校验
     * @param wk 操作空间
     */
    private void b(XLSXWorkSpace wk){
        //属性名重复校验
        List<String> propertyNameList = new ArrayList<String>();
        for (String propertyName : wk.getPropertyNameList()) {
            if (!StringUtils.hasLength(propertyName)){
                throw new XLSXParseException("第二行属性名存在空值");
            }
            propertyNameList.add(propertyName.replace("*",""));
        }
        Set<String> distictSet = new HashSet<String>(propertyNameList);
        if (propertyNameList.size() != distictSet.size()){
            throw new XLSXParseException("第二行属性名重复");
        }
    }

    private void e(a a){
        String columnName = a.getCn1();
        if (columnName.endsWith("*")){
            a.setCn1(columnName.replace("*",""));
            a.setVa(false);
        }
    }

    /**
     * 行数据解析、转换
     * @param originalValue
     */
    public String parseColumnValue(String originalValue){
        if ("NULL_VALUE".equals(originalValue)){
            return "";
        } else {
            return originalValue;
        }
    }

    /**
     * 处理前置校验
     * @param workSpace
     * @param params
     */
    public abstract void preProcess(XLSXWorkSpace workSpace,Map<String, Object> params);

    /**
     * 行数据处理
     * @param context 行数据上下文
     * @param params 参数
     */
    public abstract void doRowProcess(XLSXRowContext context,Map<String, Object> params);

    /**
     * 行数据处理逻辑异常回调函数
     * @param context
     * @param params
     */
    public void doRowError(XLSXRowContext context,Map<String, Object> params,Exception exception){
        context.appendWrite(exception.getMessage(),ContentType.FAILED);
    }

    /**
     * 行数据后置处理
     * @param context
     * @param params
     */
    public void doRowFinally(XLSXRowContext context, Map<String, Object> params) {

    }

    private void c(MultipartFile file){
        if (file == null){
            throw new XLSXParseException("文件不能为空[NULL]");
        }

        if (!file.getOriginalFilename().endsWith(".xlsx")){
            throw new XLSXParseException("文件类型错误");
        }
    }

    private Processor getProcessorAnno(){
        return this.getClass().getAnnotation(Processor.class);
    }
}
